package cn.zhl.stream;

import cn.zhl.lambda.Person;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @program: demos
 * @description:
 * @author: 刘振华
 * @create: 2020-04-22 15:24
 **/
public class StreamTest {
	@Test
	public void test1() {
		//流的创建方法
//        Stream<String> sm1 = Stream.<String>builder()
//                .add("e")
//                .add("b")
//                .add("c")
//                .add("d")
//                .add("a")
//                .build();
//        sm1.sorted(String::compareTo).forEach(System.out::println);
//        sm1.sorted(Comparator.reverseOrder()).forEach(System.out::println);
//        Stream<String> sm2 = Stream.of("a", "e", "f", "z");
//        Stream<String> sm3 = Arrays.stream(new String[]{"z","n","a","g"});
//        int[] ints = {9, 4, 8, 1, 0};
//        IntStream intts= IntStream.of(ints);
		IntStream.range(0, 5).forEach(System.out::println);

	}

	@Test
	public void test2() {
		//有一个数字流，将每一个数字*2，然后想加出结果
		int[] ints = {1, 3, 2, 4, 0};
		int sum = IntStream.of(ints).map(a -> a << 1).sum();
		System.out.println(sum);
	}

	/**
	 * 流转换为数组
	 */
	@Test
	public void test3() {
		Stream<String> sm = Stream.of("hello", "my", "name", "is", "lilei");
		String[] strs = sm.toArray(len -> {
			System.out.println("=========" + len);
			return new String[len];
		});
//        String[] strs = sm.toArray(String[]::new);
		Arrays.asList(strs).forEach(System.out::println);
	}

	/**
	 * 流转换为list数组
	 */
	@Test
	public void test4() {
		Stream<String> sm = Stream.of("hello", "my", "name", "is", "lilei");
//        List<String> cs = sm.collect(Collectors.toList());
//        List<String> cs = sm.collect(() -> new ArrayList<>(),List::add,List::containsAll);
		List<String> cs = sm.collect(ArrayList::new, List::add, List::containsAll);
//        List<String> cs = sm.collect(() -> new ArrayList<String>(), new BiConsumer<ArrayList<String>, String>() {
//            @Override
//            public void accept(ArrayList<String> strings, String s) {
//                strings.add(s);
//            }
//        }, new BiConsumer<ArrayList<String>, ArrayList<String>>() {
//            @Override
//            public void accept(ArrayList<String> strings, ArrayList<String> strings2) {
//
//            }
//        });
		System.out.println(cs);
	}

	@Test
	public void test5() {
//        Stream<String> sm = Stream.of("hello","my","name","is","lilei");
//        sm.forEach(s->System.out.println(s.toUpperCase()));
//        sm.collect(ArrayList::new,(list,s)->list.add(s.toUpperCase()),List::addAll)
//                .forEach(s->System.out.println(s));
//        sm.map(String::toUpperCase).collect(Collectors.toList()).forEach(System.out::println);
//        List<Integer> nums = Arrays.asList(3,2,7,9,3,4,5);
//        nums.stream().map(Math::sqrt).collect(Collectors.toList()).forEach(System.out::println);
	}

	@Test
	public void test6() {
		Stream<List<Integer>> sm = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));
		List<Integer> rs = sm.flatMap(List::stream).map(a -> a * a).collect(Collectors.toList());

		rs.forEach(System.out::println);

	}

	/**
	 * iterate方式，如果没有限制则会无限循环
	 */
	@Test
	public void test7() {
//        1,4,7,10,13,16
//        long count = Stream.iterate(1, a -> a + 3).limit(6)
//                .filter(a -> a > 4).map(a -> a * 2).skip(2L).limit(1L).reduce(0,(a,b)->a+b);
//        long count = Stream.iterate(1, a -> a + 2).limit(20)
//                .filter(a -> a > 4).mapToInt(a -> a * 2).skip(2L).limit(5L).reduce(0,(a,b)->a+b);
//        System.out.println(count);
		IntSummaryStatistics iss = Stream.iterate(1, a -> a + 2).limit(20)
			.filter(a -> a > 4).mapToInt(a -> a * 2).skip(2L).limit(5L).summaryStatistics();
		System.out.println(iss);
	}

	@Test
	public void test8() {
		IntStream.iterate(0, item -> (item + 1) % 2).distinct().limit(1).forEach(System.out::println);
	}

	@Test
	public void test9() {
		List<String> list = new ArrayList<>(5000000);
		for (int i = 0; i < 5000000; i++) {
			list.add(UUID.randomUUID().toString());
		}
		System.out.println("开始排序");
		long start = System.nanoTime();
		list.stream().sorted().count();
		long end = System.nanoTime();
		System.out.println(String.format("stream耗时%d", TimeUnit.NANOSECONDS.toMillis(end - start)));
	}

	@Test
	public void test10() {
		List<String> list = new ArrayList<>(5000000);
		for (int i = 0; i < 5000000; i++) {
			list.add(UUID.randomUUID().toString());
		}
		System.out.println("开始排序");
		long start = System.nanoTime();
		list.parallelStream().sorted().count();
		long end = System.nanoTime();
		System.out.println(String.format("parallelStream耗时%d", TimeUnit.NANOSECONDS.toMillis(end - start)));
	}

	@Test
	public void test11() {
		//找到长度为5的第一个字符串，然后将长度5打印出来
		List<String> list = Arrays.asList("a", "b", "heelo", "mymod", "hellowrod");
//        list.stream().filter(s->s.length()==5).findAny().ifPresent(s->System.out.println(s.length()));
		list.stream().mapToInt(String::length).filter(len -> len == 5).findFirst().ifPresent(System.out::println);
	}

	/**
	 * 去重
	 */
	@Test
	public void test12() {
		List<String> list = Arrays.asList("hello world", "world hello", "world welcome hello");
//        list.stream().flatMap(s->Arrays.asList(s.split(" ")).stream()).distinct().forEach(System.out::println);
		list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).distinct().forEach(System.out::println);
	}

	/**
	 * 分配
	 */
	@Test
	public void test13() {
		List<String> list1 = Arrays.asList("hi", "hello", "你好");
		List<String> list2 = Arrays.asList("张飞", "关羽", "刘备", "赵云");
//        list1.stream().forEach(s->{
//            list2.stream().forEach(n->{
//                System.out.println(s+","+n);
//            });
//        });
		list1.stream().flatMap(s1 -> list2.stream().map(s2 -> s1 + " " + s2)).forEach(System.out::println);
	}

	/**
	 * 分组
	 * 分区
	 */
	@Test
	public void test14() {
		Person p1 = Person.builder().name("a").age(10).score(90).build();
		Person p2 = Person.builder().name("b").age(11).score(80).build();
		Person p3 = Person.builder().name("c").age(12).score(80).build();
		Person p4 = Person.builder().name("a").age(10).score(80).build();
		List<Person> ps = Arrays.asList(p1, p2, p3, p4);
		//分组以后得到对象列表
//        Map<String, List<Person>> cs = ps.stream().collect(Collectors.groupingBy(Person::getName));
		//分组以后得到数量
//        Map<String, Long> cs = ps.stream().collect(Collectors.groupingBy(Person::getName, Collectors.counting()));
//        Map<String, Double> cs = ps.stream().collect(Collectors.groupingBy(Person::getName, Collectors.averagingInt(Person::getScore)));
//        Map<Boolean, List<Person>> cs = ps.stream().collect(Collectors.partitioningBy(p -> p.getScore() > 85));
//        Map<Boolean, Long> cs = ps.stream().collect(Collectors.partitioningBy(p -> p.getScore() > 85, Collectors.counting()));
		Collector<Person, ?, IntSummaryStatistics> pisc = Collectors.summarizingInt(Person::getScore);
		Map<String, IntSummaryStatistics> cs = ps.stream().collect(Collectors.groupingBy(Person::getName, pisc));
		System.out.println(cs);
	}

	/**
	 * collector收集器
	 * 多级分组
	 */
	@Test
	public void test15() {
		Person p111 = Person.builder().nj("一年级").bj("一班").zu("一组").name("a").age(9).score(85).build();
		Person p112 = Person.builder().nj("一年级").bj("一班").zu("二组").name("b").age(10).score(90).build();
		Person p113 = Person.builder().nj("一年级").bj("一班").zu("三组").name("c").age(11).score(95).build();
		Person p121 = Person.builder().nj("一年级").bj("二班").zu("一组").name("d").age(10).score(70).build();
		Person p122 = Person.builder().nj("一年级").bj("二班").zu("二组").name("e").age(9).score(80).build();
		Person p123 = Person.builder().nj("一年级").bj("二班").zu("三组").name("f").age(11).score(90).build();
		Person p211 = Person.builder().nj("二年级").bj("一班").zu("一组").name("g").age(11).score(100).build();
		Person p212 = Person.builder().nj("二年级").bj("一班").zu("二组").name("h").age(12).score(90).build();
		Person p213 = Person.builder().nj("二年级").bj("一班").zu("三组").name("i").age(12).score(90).build();
		List<Person> ps = Arrays.asList(p111, p112, p113, p121, p122, p123, p211, p212, p213);
//        ps.stream().collect(Collectors.maxBy(Comparator.comparingInt(Person::getScore))).ifPresent(System.out::println);
//        long l = ps.stream().collect(Collectors.averagingInt(Person::getScore)).longValue();
//        System.out.println(l);
//        System.out.println(ps.stream().map(Person::getName).collect(Collectors.joining()));
//        System.out.println(ps.stream().map(Person::getName).collect(Collectors.joining(" ")));
//        System.out.println(ps.stream().map(Person::getName).collect(Collectors.joining(" ","[","]")));
		//按照年级  班级  小组 进行分组
//        Map<String,Map<String, Map<String, List<Person>>>> trs = ps.stream().collect(Collectors.groupingBy(Person::getNj, Collectors.groupingBy(Person::getBj,Collectors.groupingBy(Person::getZu))));
//        trs.keySet().stream().forEach(t1->{
//            Map<String, Map<String, List<Person>>> rs = trs.get(t1);
//            rs.keySet().stream().forEach(s->{
//                Map<String, List<Person>> tsm = rs.get(s);
//                tsm.keySet().stream().forEach(ts->{
//                    System.out.print(t1+"\t");
//                    System.out.print(s+"\t");
//                    System.out.print(ts+"\t");
//                    System.out.println(tsm.get(ts));
//                });
//            });
//        });
//        Map<Boolean, Map<Boolean, List<Person>>> frs = ps.stream()
//                .collect(Collectors.partitioningBy(p -> p.getNj().equals("一年级")
//                        , Collectors.partitioningBy(p -> p.getAge() > 10)
//                ));
//        frs.keySet().stream().forEach(key1->{
//            Map<Boolean, List<Person>> map1 = frs.get(key1);
//            map1.keySet().stream().forEach(key2->{
//                System.out.print(key1+"\t");
//                System.out.print(key2+"\t");
//                System.out.println(map1.get(key2));
//            });
//        });
		//根据年级分组，找到年级分数的最大值
		Map<String, Person> rp = ps.stream().collect(Collectors.groupingBy(Person::getNj,
			Collectors.collectingAndThen(
				Collectors.maxBy(Comparator.comparingInt(Person::getScore)),
				Optional::get)));
		System.out.println(rp);

	}

	//onClose方法何时被调用，close时被调用
	//使用try  with  resource可是实现
	@Test
	public void test16() {
		List<Integer> list = Arrays.asList(3, 5, 6, 7, 8, 9, 0, 0);
		try (Stream<Integer> stream = list.stream();) {
			stream.onClose(() -> {
				System.out.println("first close");
				throw new NullPointerException("aaa");
			}).onClose(() -> {
				System.out.println("second close");
				throw new NullPointerException("bbb");
			}).forEach(System.out::println);
		}


	}
}
